/* eslint-disable @typescript-eslint/no-explicit-any */
import type { BaseOptions, BaseResult, OptionsWithFormat } from '@ahooksjs/use-request/es/types';
import useAsync from '@ahooksjs/use-request/es/useAsync';
import { useState } from 'react';
import { asyncFunction } from '..';
import type { ResponseResult, Service } from './type';

type OmitInitialDataOption<R = any, P extends any[] = any> = Omit<BaseOptions<R, P>, 'initialData'>;
type OptionWithInitialData<R = any, P extends any[] = any> = OmitInitialDataOption<R, P> & {
  initialData: R;
};
type RequestResult<R = any, P extends any[] = any> = Omit<BaseResult<R, P>, 'run'> & {
  ok: boolean;
  run: (...args: P) => Promise<boolean>;
};
type ResultWithInitialData<R = any, P extends any[] = any> = RequestResult<R, P> & {
  data: R;
};

/**
 * hook形式的 http请求
 *
 * 基于 https://hooks.umijs.org/zh-CN/hooks/async
 * @param {function|promise} service 请求方法
 * @param {object} options 请求配置
 * @returns 请求数据对象，包括loading、data、error等
 */
function useRequest<R = any, P extends any[] = any, U = any, UU extends U = any>(
  service: Service<R, P>,
  options: OptionsWithFormat<R, P, U, UU>
): RequestResult<U, P>;
function useRequest<R = any, P extends any[] = any>(
  service: Service<R, P>,
  options?: OmitInitialDataOption<R, P>
): RequestResult<R, P>;

function useRequest<R = any, P extends any[] = any>(
  service: Service<R, P>,
  options?: OptionWithInitialData<R, P>
): ResultWithInitialData<R, P>;
// eslint-disable-next-line require-jsdoc
function useRequest(service: unknown, options: Record<string, unknown> = {}): unknown {
  const [ok, setOk] = useState(false);
  if (typeof service !== 'function') throw new Error('service should be a function!');
  const promiseService = (...args: unknown[]) =>
    new Promise((resolve, reject) => {
      service(...args).then((data: ResponseResult<unknown> | ResponseResult<unknown>[]) => {
        if (data instanceof Array) {
          resolve(data);
        } else if (data.ok) {
          resolve(data.data);
        } else {
          reject(data.err);
        }
      });
    });
  const result = useAsync(promiseService, {
    throwOnError: true,
    ...options
  });
  const run = async (...args: any[]) => {
    const res = await asyncFunction(result.run, ...args);
    setOk(res.ok);
    return res.ok;
  };

  return { ...result, run, ok };
}
export default useRequest;
